package jmine.tec.rpc.checkup;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;

import jmine.tec.rpc.common.serialization.Serializer;
import jmine.tec.rpc.common.serialization.SerializerBuilder;

import org.apache.commons.beanutils.ConstructorUtils;

/**
 * @author lundberg
 * @param <R> tipo da representação
 */
public class RepresentationSerializationCheckup<R> {

    private final R representation;

    private Serializer serializer;

    /**
     * @param representationClass representationClass
     * @throws Exception Exception
     */
    public RepresentationSerializationCheckup(Class<R> representationClass) throws Exception {
        this(representationClass.cast(ConstructorUtils.invokeConstructor(representationClass, new Object[0])));
    }

    /**
     * @param representationClass representationClass
     * @param serializer serializer
     * @throws Exception Exception
     */
    public RepresentationSerializationCheckup(Class<R> representationClass, Serializer serializer) throws Exception {
        this(representationClass.cast(ConstructorUtils.invokeConstructor(representationClass, new Object[0])), serializer);
    }

    /**
     * @param representation representation
     */
    public RepresentationSerializationCheckup(R representation) {
        this(representation, SerializerBuilder.aSerializer().build());
    }

    /**
     * @param representation representation
     * @param serializer serializer
     */
    public RepresentationSerializationCheckup(R representation, Serializer serializer) {
        this.representation = representation;
        this.serializer = serializer;
    }

    /**
     * Verifica se a representação pode ser serializada e deserializada.
     */
    public void check() {
        this.testSerializationFor(this.representation);
    }

    /**
     * Tests serialization of a given object
     * 
     * @param original original object
     */
    protected void testSerializationFor(Object original) {
        Object deserialized = this.serializeAndDeserialize(original);
        assertThat("Unmarshalled an original do not match.", deserialized, is(equalTo((original))));
    }

    /**
     * @param original original
     * @return result
     */
    protected Object serializeAndDeserialize(Object original) {
        try {
            InputStream stream = this.serializer.serialize(original);
            return this.serializer.deserialize(stream);
        } catch (IOException e) {
            fail(e.getMessage());
            throw new IllegalStateException();
        } catch (ParseException e) {
            fail(e.getMessage());
            throw new IllegalStateException();
        }
    }

}
